﻿using GeneticAlgorithms.Genomes;
using GeneticAlgorithms.Tools;

namespace GeneticAlgorithms.Operators.Mutation
{
    /// <summary>
    /// Base class for mutation operators.
    /// </summary>
    /// <typeparam name="TGene">The type of the gene.</typeparam>
    public abstract class BaseMutator<TGene> : IGeneticMutator<TGene>
    {
        #region IGeneticMutator<object> Members

        /// <summary>
        /// Gets or sets the mutation probability.
        /// </summary>
        /// <value>The mutation probability.</value>
        public double MutationProbability
        {
            get;
            set;
        }

        /// <summary>
        /// Mutates the specified genome.
        /// </summary>
        /// <param name="genome">The genome.</param>
        public void Mutate(IGenome<TGene> genome)
        {
            TraceHelper.WriteLine("Applying mutation to genome: {0}", genome);
            for (int i = 0; i < genome.Length; ++i)
            {
                if (GeneticRandomGenerator.Default.NextBool(MutationProbability))
                {
                    TGene previous = genome[i];
                    MutateGene(genome, i);
                    TraceHelper.WriteLine(
                        "Changing gene {0} from {1} to {2}",
                        i, 
                        previous, 
                        genome[i]);
                }
            }
        }

        #endregion

        /// <summary>
        /// Mutates a specific gene.
        /// </summary>
        /// <param name="genome">The genome whose gene will be mutated.</param>
        /// <param name="position">The gene position.</param>
        protected abstract void MutateGene(IGenome<TGene> genome, int position);
    }
}
